package fr.inria.phoenix.diasuite.framework.context.cookerready;

import fr.inria.diagen.core.ServiceConfiguration;
import fr.inria.diagen.core.exception.InvocationException;
import fr.inria.diagen.core.service.composite.CompositeException;
import fr.inria.diagen.core.network.RemoteServiceInfo;
import fr.inria.diagen.core.service.local.Service;
import fr.inria.diagen.core.service.proxy.Proxy;

import fr.inria.phoenix.diasuite.framework.device.cooker.StatusFromCooker;

/**
 * <pre>
context CookerReady as Boolean{
 * 	when provided status from Cooker 
 * 	get currentElectricConsumption from ElectricMeter
 * 	always publish;
 * }
</pre>
 */
@SuppressWarnings("all")
public abstract class AbstractCookerReady extends Service {
    
    public AbstractCookerReady(ServiceConfiguration serviceConfiguration) {
        super("/Context/CookerReady/", serviceConfiguration);
    }
    
    // Methods from the Service class
    @Override
    protected final void internalPostInitialize() {
        postInitialize();
    }
    
    @Override
    protected void postInitialize() {
        // Default implementation of post initialize: subscribe to all required devices
        discoverCookerForSubscribe.all().subscribeStatus(); // subscribe to status from all Cooker devices
    }
    
    @Override
    public final void valueReceived(java.util.Map<String, Object> properties, RemoteServiceInfo source, String eventName, Object value, Object... indexes) {
        if (eventName.equals("status") && source.isCompatible("/Device/Device/PhysicalDevice/Appliance/Cooker/")) {
            StatusFromCooker statusFromCooker = new StatusFromCooker(this, source, (fr.inria.phoenix.diasuite.framework.datatype.onoffstatus.OnOffStatus) value);
            
            setCookerReady(onStatusFromCooker(statusFromCooker, new DiscoverForStatusFromCooker()));
        }
    }
    
    @Override
    public final Object getValueCalled(java.util.Map<String, Object> properties, RemoteServiceInfo source, String valueName,
            Object... indexes) throws Exception {
        if (valueName.equals("cookerReady")) {
            return getLastValue();
        }
        throw new InvocationException("Unsupported method call: " + valueName);
    }
    // End of methods from the Service class
    
    // Code relative to the return value of the context
    private java.lang.Boolean contextValue;
    
    private void setCookerReady(java.lang.Boolean newContextValue) {
        contextValue = newContextValue;
        getProcessor().publishValue(getOutProperties(), "cookerReady", newContextValue);
    }
    
    /**
     * Get the last value of the context
     * 
     * @return the latest value published by the context
     */
    protected final java.lang.Boolean getLastValue() {
        return contextValue;
    }
    // End of code relative to the return value of the context
    
    // Interaction contract implementation
    /**
     * This method is called when a <code>Cooker</code> device on which we have subscribed publish on its <code>status</code> source.
    
    <pre>
    when provided status from Cooker 
     * 	get currentElectricConsumption from ElectricMeter
     * 	always publish;
    </pre>
     * 
     * @param statusFromCooker the value of the <code>status</code> source and the <code>Cooker</code> device that published the value.
     * @param discover a discover object to get value from devices and contexts
     * @return the value to publish
     */
    protected abstract java.lang.Boolean onStatusFromCooker(StatusFromCooker statusFromCooker, DiscoverForStatusFromCooker discover);
    
    // End of interaction contract implementation
    
    // Discover part for Cooker devices
    /**
     * Use this object to discover Cooker devices.
    
    <pre>
    device Cooker extends Appliance {
    }
    </pre>
     * 
     * @see CookerDiscoverer
     */
    protected final CookerDiscoverer discoverCookerForSubscribe = new CookerDiscoverer(this);
    
    /**
     * Discover object that will exposes the <code>Cooker</code> devices that can be discovered
    
    <pre>
    device Cooker extends Appliance {
    }
    </pre>
     */
    protected final static class CookerDiscoverer {
        private Service serviceParent;
        
        private CookerDiscoverer(Service serviceParent) {
            super();
            this.serviceParent = serviceParent;
        }
        
        private CookerComposite instantiateComposite() {
            return new CookerComposite(serviceParent);
        }
        
        /**
         * Returns a composite of all accessible <code>Cooker</code> devices
         * 
         * @return a {@link CookerComposite} object composed of all discoverable <code>Cooker</code>
         */
        public CookerComposite all() {
            return instantiateComposite();
        }
        
        /**
         * Returns a proxy to one out of all accessible <code>Cooker</code> devices
         * 
         * @return a {@link CookerProxy} object pointing to a random discoverable <code>Cooker</code> device
         */
        public CookerProxy anyOne() {
            return all().anyOne();
        }
        
        /**
         * Returns a composite of all accessible <code>Cooker</code> devices whose attribute <code>id</code> matches a given value.
         * 
         * @param id The <code>id<code> attribute value to match.
         * @return a {@link CookerComposite} object composed of all matching <code>Cooker</code> devices
         */
        public CookerComposite whereId(java.lang.String id) throws CompositeException {
            return instantiateComposite().andId(id);
        }
        
        /**
         * Returns a composite of all accessible <code>Cooker</code> devices whose attribute <code>location</code> matches a given value.
         * 
         * @param location The <code>location<code> attribute value to match.
         * @return a {@link CookerComposite} object composed of all matching <code>Cooker</code> devices
         */
        public CookerComposite whereLocation(java.lang.String location) throws CompositeException {
            return instantiateComposite().andLocation(location);
        }
        
        /**
         * Returns a composite of all accessible <code>Cooker</code> devices whose attribute <code>user</code> matches a given value.
         * 
         * @param user The <code>user<code> attribute value to match.
         * @return a {@link CookerComposite} object composed of all matching <code>Cooker</code> devices
         */
        public CookerComposite whereUser(java.lang.String user) throws CompositeException {
            return instantiateComposite().andUser(user);
        }
    }
    
    /**
     * A composite of several <code>Cooker</code> devices
    
    <pre>
    device Cooker extends Appliance {
    }
    </pre>
     */
    protected final static class CookerComposite extends fr.inria.diagen.core.service.composite.Composite<CookerProxy> {
        private CookerComposite(Service serviceParent) {
            super(serviceParent, "/Device/Device/PhysicalDevice/Appliance/Cooker/");
        }
        
        @Override
        protected CookerProxy instantiateProxy(RemoteServiceInfo rsi) {
            return new CookerProxy(service, rsi);
        }
        
        /**
         * Returns this composite in which a filter was set to the attribute <code>id</code>.
         * 
         * @param id The <code>id<code> attribute value to match.
         * @return this {@link CookerComposite}, filtered using the attribute <code>id</code>.
         */
        public CookerComposite andId(java.lang.String id) throws CompositeException {
            filterByAttribute("id", id);
            return this;
        }
        
        /**
         * Returns this composite in which a filter was set to the attribute <code>location</code>.
         * 
         * @param location The <code>location<code> attribute value to match.
         * @return this {@link CookerComposite}, filtered using the attribute <code>location</code>.
         */
        public CookerComposite andLocation(java.lang.String location) throws CompositeException {
            filterByAttribute("location", location);
            return this;
        }
        
        /**
         * Returns this composite in which a filter was set to the attribute <code>user</code>.
         * 
         * @param user The <code>user<code> attribute value to match.
         * @return this {@link CookerComposite}, filtered using the attribute <code>user</code>.
         */
        public CookerComposite andUser(java.lang.String user) throws CompositeException {
            filterByAttribute("user", user);
            return this;
        }
        
        /**
         * Subscribes to the <code>status</code> source. After a call to this method, the context will be notified when a
         * <code>Cooker</code> device of this composite publishes a value on its <code>status</code> source.
         */
        public void subscribeStatus() {
            subscribeValue("status");
        }
        
        /**
         * Unsubscribes from the <code>status</code> source. After a call to this method, the context will no more be notified
         * when a <code>Cooker</code> device of this composite publishes a value on its <code>status</code> source.
         */
        public void unsubscribeStatus() {
            unsubscribeValue("status");
        }
    }
    
    /**
     * A proxy to one <code>Cooker</code> device
    
    <pre>
    device Cooker extends Appliance {
    }
    </pre>
     */
    protected final static class CookerProxy extends Proxy {
        private CookerProxy(Service service, RemoteServiceInfo remoteServiceInfo) {
            super(service, remoteServiceInfo);
        }
        
        /**
         * Subscribes to the <code>status</code> source. After a call to this method, the context will be notified when the
         * <code>Cooker</code> device of this proxy publishes a value on its <code>status</code> source.
         */
        public void subscribeStatus() {
            subscribeValue("status");
        }
        
        /**
         * Unsubscribes from the <code>status</code> source. After a call to this method, the context will no more be notified
         * when the <code>Cooker</code> device of this proxy publishes a value on its <code>status</code> source.
         */
        public void unsubscribeStatus() {
            unsubscribeValue("status");
        }
        
        /**
         * @return the value of the <code>id</code> attribute
         */
        public java.lang.String id() {
            return (java.lang.String) callGetValue("id");
        }
        
        /**
         * @return the value of the <code>location</code> attribute
         */
        public java.lang.String location() {
            return (java.lang.String) callGetValue("location");
        }
        
        /**
         * @return the value of the <code>user</code> attribute
         */
        public java.lang.String user() {
            return (java.lang.String) callGetValue("user");
        }
    }
    // End of discover part for Cooker devices
    
    // Discover object for status from Cooker
    /**
     * An object to discover devices and contexts for the following interaction contract:
     * 
     * <code>
     * when provided status from Cooker 
     * 	get currentElectricConsumption from ElectricMeter
     * 	always publish;
     * </code>
     */
    protected final class DiscoverForStatusFromCooker {
        private final ElectricMeterDiscovererForStatusFromCooker electricMeterDiscoverer = new ElectricMeterDiscovererForStatusFromCooker(AbstractCookerReady.this);
        
        /**
         * @return a {@link ElectricMeterDiscovererForStatusFromCooker} object to discover <code>ElectricMeter</code> devices
         */
        public ElectricMeterDiscovererForStatusFromCooker electricMeters() {
            return electricMeterDiscoverer;
        }
    }
    
    /**
     * Discover object that will exposes the <code>ElectricMeter</code> devices to get their sources for the
     * <code>when provided status from Cooker</code> interaction contract.
    
    <pre>
    device ElectricMeter extends EnergyMeter {
    	source currentElectricConsumption as Float;
    }
    </pre>
     */
    protected final static class ElectricMeterDiscovererForStatusFromCooker {
        private Service serviceParent;
        
        private ElectricMeterDiscovererForStatusFromCooker(Service serviceParent) {
            super();
            this.serviceParent = serviceParent;
        }
        
        private ElectricMeterCompositeForStatusFromCooker instantiateComposite() {
            return new ElectricMeterCompositeForStatusFromCooker(serviceParent);
        }
        
        /**
         * Returns a composite of all accessible <code>ElectricMeter</code> devices
         * 
         * @return a {@link ElectricMeterCompositeForStatusFromCooker} object composed of all discoverable <code>ElectricMeter</code>
         */
        public ElectricMeterCompositeForStatusFromCooker all() {
            return instantiateComposite();
        }
        
        /**
         * Returns a proxy to one out of all accessible <code>ElectricMeter</code> devices
         * 
         * @return a {@link ElectricMeterProxyForStatusFromCooker} object pointing to a random discoverable <code>ElectricMeter</code> device
         */
        public ElectricMeterProxyForStatusFromCooker anyOne() {
            return all().anyOne();
        }
        
        /**
         * Returns a composite of all accessible <code>ElectricMeter</code> devices whose attribute <code>id</code> matches a given value.
         * 
         * @param id The <code>id<code> attribute value to match.
         * @return a {@link ElectricMeterCompositeForStatusFromCooker} object composed of all matching <code>ElectricMeter</code> devices
         */
        public ElectricMeterCompositeForStatusFromCooker whereId(java.lang.String id) throws CompositeException {
            return instantiateComposite().andId(id);
        }
        
        /**
         * Returns a composite of all accessible <code>ElectricMeter</code> devices whose attribute <code>location</code> matches a given value.
         * 
         * @param location The <code>location<code> attribute value to match.
         * @return a {@link ElectricMeterCompositeForStatusFromCooker} object composed of all matching <code>ElectricMeter</code> devices
         */
        public ElectricMeterCompositeForStatusFromCooker whereLocation(java.lang.String location) throws CompositeException {
            return instantiateComposite().andLocation(location);
        }
        
        /**
         * Returns a composite of all accessible <code>ElectricMeter</code> devices whose attribute <code>user</code> matches a given value.
         * 
         * @param user The <code>user<code> attribute value to match.
         * @return a {@link ElectricMeterCompositeForStatusFromCooker} object composed of all matching <code>ElectricMeter</code> devices
         */
        public ElectricMeterCompositeForStatusFromCooker whereUser(java.lang.String user) throws CompositeException {
            return instantiateComposite().andUser(user);
        }
    }
    
    /**
     * A composite of several <code>ElectricMeter</code> devices to get their sources for the
     * <code>when provided status from Cooker</code> interaction contract.
    
    <pre>
    device ElectricMeter extends EnergyMeter {
    	source currentElectricConsumption as Float;
    }
    </pre>
     */
    protected final static class ElectricMeterCompositeForStatusFromCooker extends fr.inria.diagen.core.service.composite.Composite<ElectricMeterProxyForStatusFromCooker> {
        private ElectricMeterCompositeForStatusFromCooker(Service serviceParent) {
            super(serviceParent, "/Device/Device/PhysicalDevice/Sensor/EnergyMeter/ElectricMeter/");
        }
        
        @Override
        protected ElectricMeterProxyForStatusFromCooker instantiateProxy(RemoteServiceInfo rsi) {
            return new ElectricMeterProxyForStatusFromCooker(service, rsi);
        }
        
        /**
         * Returns this composite in which a filter was set to the attribute <code>id</code>.
         * 
         * @param id The <code>id<code> attribute value to match.
         * @return this {@link ElectricMeterCompositeForStatusFromCooker}, filtered using the attribute <code>id</code>.
         */
        public ElectricMeterCompositeForStatusFromCooker andId(java.lang.String id) throws CompositeException {
            filterByAttribute("id", id);
            return this;
        }
        
        /**
         * Returns this composite in which a filter was set to the attribute <code>location</code>.
         * 
         * @param location The <code>location<code> attribute value to match.
         * @return this {@link ElectricMeterCompositeForStatusFromCooker}, filtered using the attribute <code>location</code>.
         */
        public ElectricMeterCompositeForStatusFromCooker andLocation(java.lang.String location) throws CompositeException {
            filterByAttribute("location", location);
            return this;
        }
        
        /**
         * Returns this composite in which a filter was set to the attribute <code>user</code>.
         * 
         * @param user The <code>user<code> attribute value to match.
         * @return this {@link ElectricMeterCompositeForStatusFromCooker}, filtered using the attribute <code>user</code>.
         */
        public ElectricMeterCompositeForStatusFromCooker andUser(java.lang.String user) throws CompositeException {
            filterByAttribute("user", user);
            return this;
        }
    }
    
    /**
     * A proxy to one <code>ElectricMeter</code> device to get its sources for the
     * <code>when provided status from Cooker</code> interaction contract.
    
    <pre>
    device ElectricMeter extends EnergyMeter {
    	source currentElectricConsumption as Float;
    }
    </pre>
     */
    protected final static class ElectricMeterProxyForStatusFromCooker extends Proxy {
        private ElectricMeterProxyForStatusFromCooker(Service service, RemoteServiceInfo remoteServiceInfo) {
            super(service, remoteServiceInfo);
        }
        
        /**
         * Returns the value of the <code>currentElectricConsumption</code> source of this <code>ElectricMeter</code> device
         * 
         * @return the value of the <code>currentElectricConsumption</code> source
         */
        public java.lang.Float getCurrentElectricConsumption() throws InvocationException {
            return (java.lang.Float) callGetValue("currentElectricConsumption");
        }
        
        /**
         * @return the value of the <code>id</code> attribute
         */
        public java.lang.String id() {
            return (java.lang.String) callGetValue("id");
        }
        
        /**
         * @return the value of the <code>location</code> attribute
         */
        public java.lang.String location() {
            return (java.lang.String) callGetValue("location");
        }
        
        /**
         * @return the value of the <code>user</code> attribute
         */
        public java.lang.String user() {
            return (java.lang.String) callGetValue("user");
        }
    }
    // End of discover object for status from Cooker
}
